import { defineComponent, nextTick, onMounted, ref,watch } from 'vue';
import { mxgraph } from './mxgraph';
import { useEditor } from '@jecloud/ui/src/editor-code/src/hooks/use-editor';
import { useEditorUi } from './mxgraph/src/EditorUi';
import { Panel,Modal } from '@jecloud/ui';
import { loadMxGraph } from './mxgraph/utils';
import { isEmpty, isNotEmpty} from '@jecloud/utils';
import {JE_DEITORDRAW_NODEDATA} from '@/helper/constant'

export default defineComponent({
  name: 'JeEditorDraw',
  inheritAttrs: false,
  props: {
    value: { type: String, default: '' },
    width: [String, Number],
    height: { type: [String, Number], default: 400 },
    jebpmData:{type:Object},
    editorOptions: Object,
    editorXml:{type:String}
  },
  emits: ['update:value','nodeChange','nodeLabelChange','nodeRemove'],
  setup(props, context) {
    const { slots, attrs, emit, expose } = context;
    const { value, style, $plugin } = useEditor({ props, context });
    const $el = ref();
    const $coreSidebar = ref();
    const $synergiaSidebar =ref();
    const $editor = ref();
    const $editorUi = ref();
    const $PrintDialog = ref();
    const $outline = ref();
    

    const publicPath = '';//ConfigProvider.getGlobalConfig('publicPath', '/');
    
    //添加自定义节点
    const addCoreSidebarNode = function (ui, mxUtils, coreSidebar) {
      ui.editor.taskStyles = {};
      var wfItems = JE_DEITORDRAW_NODEDATA;
      var doc = mxUtils.createXmlDocument();
      var sidebar = coreSidebar,
        fns = [],
        width = 48,
        height = 48;
      wfItems.forEach((n) => {
        var node = doc.createElement(n.node || 'node');
        node.setAttribute('label', n.label || '');
        node.setAttribute('name', n.value);
        node.setAttribute('type', n.node || '');
        var value = node;
        var style =n.style;
        if (isEmpty(n.node)) {
          ui.editor.taskStyles[n.node] = style;
        }
        var showLabel = node.getAttribute('label') != '';
        var fn = sidebar.createVertexTemplateEntry(
          style,
          n.width || width,
          n.height || height,
          value,
          n.value,
          showLabel,
          true,
        );
        fns.push(fn);
      });
      sidebar.addPaletteFunctions($coreSidebar.value, '', false, fns);
    };
    
    //判断连线是否正确
    const decideLine=(sender, evt)=>{
      var edge = evt.getProperty('edge');
      if (edge && edge.target && edge.source) {
        //source 起点,target出口
        const source = edge.source,target = edge.target;
        
        if(isEmpty(source.getAttribute('type')) || isEmpty(target.getAttribute('type'))){
          Modal.alert('协同组件不可连线!','error');
          sender.removeCells([edge]);
        }

        let flag=false;
        if(source.id == target.id){
          flag = true;
          Modal.alert('连线起点和终点不能为同一个节点！','error');
          //开始节点不能有入线
        }else if(target.getAttribute('type') =='start'){
          flag = true;
          Modal.alert('开始节点不能有入线！','error');
          //结束节点不能有出线
        }else if(source.getAttribute('type') =='end'){
          flag = true;
          Modal.alert('结束节点不能有出线！','error');
          //开始节点只能连接任务和判断节点
        }else if(source.getAttribute('type') =='start' && ['decision','task'].indexOf(target.getAttribute('type'))==-1){
          flag = true;
          Modal.alert('开始节点只能连接任务和判断节点！','error');
          //分支节点只能连接任务、候选、固定人、随机、自由、多人审批、节点
        }else if(source.getAttribute('type') =='branchGateway' && ['task','joint','to_assignee','random','circular','batchtask'].indexOf(target.getAttribute('type'))==-1){
          flag = true;
          Modal.alert('分支节点只能连接任务、候选、固定人、随机、自由、多人审批！','error');
        //聚合节点只能连接聚合、固定人、随机、候选、结束节点
        }else if(source.getAttribute('type') =='aggregationGateway' && ['aggregationGateway','to_assignee','random','joint','end'].indexOf(target.getAttribute('type'))==-1){
          flag = true;
          Modal.alert('聚合节点只能连接聚合、固定人、随机、候选、结束！','error');
          //会签节点只能连接固定人、随机、候选、自由、多人审批、结束节点
        }else if(source.getAttribute('type') =='countersign' && ['to_assignee','random','joint','batchtask','end'].indexOf(target.getAttribute('type'))==-1){
          flag = true;
          Modal.alert('会签节点只能连接固定人、随机、候选、多人审批、结束节点！','error');
          //多人审批节点只能连接固定人、随机、候选、自由、多人审批、结束节点
        }else if(source.getAttribute('type') =='batchtask' && ['to_assignee','random','joint','batchtask','end','aggregationGateway'].indexOf(target.getAttribute('type'))==-1){
          flag = true;
          Modal.alert('多人审批节点只能连接固定人、随机、候选、多人审批、结束、聚合节点！','error');
        }
        const nodeData = props.jebpmData.getNodeData(source.getId());
        const logicalJudgment = nodeData && nodeData.properties.logicalJudgment;
        //任务节点只有一个出线 开启启用逻辑可以有多条
        if((['task','joint','to_assignee','random','circular'].indexOf(source.getAttribute('type')) !=-1 && logicalJudgment != '1') || ['aggregationGateway','countersign','batchtask','start'].indexOf(source.getAttribute('type')) !=-1){
          var cells = sender.getModel().root.children[0].children;
          let n=0;
          cells.forEach((item)=>{
            if((item.nodeType == 'line' || item.edge) && item.source && item.source.getId() == source.getId()){
              n++;
              if(n>=2){
                flag = true;
                Modal.alert('该节点仅有一条出线!','error');
              }
            }
          });
        }

        if(flag){
          edge.removeType = true;
         sender.removeCells([edge]);
        }
        
      }else{
        setTimeout(() => {
          if (!edge.source || !edge.target) { 
            Modal.alert('连线的起点或终点不能为空!','error');
            sender.removeCells([edge]);
          }
        }, 10);
      }
    }

    onMounted(() => {
      const me = this;
      nextTick(() => {
        loadMxGraph().then((mxgraph) => {
          const { EditorUi, Editor, Graph,PrintDialog } = useEditorUi();
          const { mxUtils, STYLE_PATH, mxEvent,mxOutline } = mxgraph;
          $PrintDialog.value = PrintDialog;
          const themes = {
            [Graph.prototype.defaultThemeName]: mxUtils
              .load(STYLE_PATH + '/default.xml')
              .getDocumentElement(),
          };
          // 节点选择改变事件
          
         
          setTimeout(() => {
            const editor = $editor.value=new Editor(false, themes);
            const ui =$editorUi.value =new EditorUi(editor, $plugin.value);
            const coreSidebar = ui.createSidebar($coreSidebar.value);
            addCoreSidebarNode(ui, mxUtils, coreSidebar);

            const synergiaSidebar = ui.createSidebar($synergiaSidebar.value);
            synergiaSidebar.addGeneralPalette(true);
            //初始化缩略图
            //const outlineContextDom = document.getElementsByClassName('editor-outline-context')[0];
            //$outline.value = new mxOutline(editor.graph,outlineContextDom);
            $outline.value = mxOutline;
            //绑定节点改变事件
            editor.graph.getSelectionModel().addListener(mxEvent.CHANGE,(sender, evt)=>{
              //节点信息
              const cell = editor.graph.getSelectionCell();
              context.emit('nodeChange',cell,evt);
            });

            // 标签改变的时候同时改变表单值
            editor.graph.addListener(mxEvent.LABEL_CHANGED, function(sender, evt) {
              const cell = evt.getProperty('cell');
              const type = cell.getAttribute('type');
              if(isNotEmpty(type)){
                const label = evt.getProperty('value');
                const oldLabel = evt.getProperty('old').getAttribute('label');
                // 标签一样，不操作
                if (label == oldLabel)
                  return;
                const obj = {
                  label : label
                };
                context.emit('nodeLabelChange',obj,cell);
              }
            });

            // 删除开始节点时清空缓存数据 不要删除逻辑先废弃
            /* editor.graph.addListener(mxEvent.REMOVE_CELLS, function(sender, evt) {
              const cells = evt.getProperty('cells');
              if(cells.length>0){
                context.emit('nodeRemove',cells);
              }
            }); */
            
            //连线事件
            editor.graph.addListener(mxEvent.CELL_CONNECTED,function(sender, evt){
              decideLine(sender, evt);
            });
            //回显xml
            if(isNotEmpty(props.editorXml)){
              const xml = decodeURIComponent(props.editorXml);
              const doc = mxgraph.mxUtils.parseXml(xml);
              const codec = new mxgraph.mxCodec(doc);
              codec.decode(doc.documentElement, editor.graph.getModel());
            }

          }, 100);
        });
      });
    });

    watch(
      () => props.editorXml,
      (newValue) => {
        if(isNotEmpty(newValue) && $editor.value){
          const xml = decodeURIComponent(newValue);
          const doc = mxgraph.mxUtils.parseXml(xml);
          const codec = new mxgraph.mxCodec(doc);
          codec.decode(doc.documentElement, $editor.value.graph.getModel());
        }
      },
    )

    const closeOutline = ()=>{
      const outlineDom = document.getElementsByClassName('editor-outline')[0];
      outlineDom.style.display = 'none';
    }

    //导出属性
    context.expose({$editor,mxgraph,$editorUi, $PrintDialog,$outline})
    return () => (
      <Panel class="je-editor-draw" ref={$el} style={{ ...style, ...attrs.style }}>
        <Panel.Item region="left" size="200" split collapsible>
          <div class="editor-draw-left-bar">
            <div class="left-title">核心组件</div>
            <div
            ref={$coreSidebar}
            style="height:440px"
            class="je-editor-draw-sidebar geSidebar"
            ></div>
            <div class="left-title synergia">协同组件</div>
            <div
            ref={$synergiaSidebar}
            style="height:120px"
            class="je-editor-draw-sidebar geSidebar"
            ></div>
        </div>
        </Panel.Item>
        <Panel.Item>
          <div class="je-editor-draw-body" ref={$plugin}>
            <div class="editor-draw-toolbar">
             {slots.bbar?.()}
            </div>
            <div class = "editor-outline" style='display:none'>
              <div class="header" style="height:30px">
                <i class="tool--btn tool--close fal fa-times" title="关闭" style='cursor: pointer;' onClick={closeOutline}></i>
              </div>
              <div class='editor-outline-context' style="height:170px"></div>
            </div>
          </div>
        </Panel.Item>
      </Panel>
    );
  },
});
